package org.simpleframework.aop;

import org.simpleframework.aop.annotation.Aspect;
import org.simpleframework.aop.annotation.Order;
import org.simpleframework.aop.aspect.AspectInfo;
import org.simpleframework.aop.aspect.DefaultAspect;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.util.*;

public class AspectWeaver {
    private BeanContainer beanContainer;

    public AspectWeaver() {
       beanContainer= BeanContainer.getInstance();
    }

    public void doAop(){
        //1。获取所有切面类
        Set<Class<?>> aspectSet = beanContainer.getClassByAnnotation(Aspect.class);
        //2.将切面类按不同织入目标进行切分
        Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap=new HashMap<>();
        if(ValidationUtil.isEmpty(aspectSet)){return;}
        for (Class<?> aspectClass : aspectSet) {
            if(verifyAspect(aspectClass)){
                categorizeAspect(categorizedMap,aspectClass);
            }else {
                throw new RuntimeException("@Aspect and @Order have not been added to the Aspect Class,"+
                        "or Aspect class does not extended from DefaultAspect,or the Value is Aspect Tag equals @Aspect");
            }
        }
        //3.按照不同的织入目标分别去按序织入Aspect的逻辑
        if (ValidationUtil.isEmpty(categorizedMap)){return;}
        for (Class<? extends Annotation> category : categorizedMap.keySet()) {
            weaveByCategory(category,categorizedMap.get(category));
        }
    }

    private void weaveByCategory(Class<? extends Annotation> category, List<AspectInfo> aspectInfoList) {
        //1.获取被代理类的集合
        Set<Class<?>> classSet = beanContainer.getClassByAnnotation(category);
        if(ValidationUtil.isEmpty(classSet))return;
        //2.遍历被代理类，分别为每个被代理类生成动态代理实例
        for (Class<?> targetClass : classSet) {
            //创建动态代理对象
            AspectListExecutor aspectListExecutor=new AspectListExecutor(targetClass,aspectInfoList);
            Object proxyBean = ProxyCreator.createProxy(targetClass, aspectListExecutor);
            //3.将动态代理实例添加到容器里，取代未被代理前的实例
            beanContainer.addBean(targetClass,proxyBean);
        }

    }

    private void categorizeAspect(Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap, Class<?> aspectClass) {
        Order orderTag=aspectClass.getAnnotation(Order.class);
        Aspect aspectTag=aspectClass.getAnnotation(Aspect.class);
      DefaultAspect aspect=  (DefaultAspect) beanContainer.getBean(aspectClass);
      AspectInfo aspectInfo=new AspectInfo(orderTag.value(),aspect);
        if(!categorizedMap.containsKey(aspectTag.value())){
          //如果织入的joinPoint第一次出现，则以该joinPoint为key,以新创建的List<AspectInfo>为value
        List<AspectInfo>aspectInfoList=new ArrayList<>();
        aspectInfoList.add(aspectInfo);
        categorizedMap.put(aspectTag.value(), aspectInfoList);
        }else {
            //如果织入的joinPoint不是第一次出现，则往joinPoint对应的value里添加新的Aspect逻辑
            List<AspectInfo> aspectInfoList = categorizedMap.get(aspectTag.value());
            aspectInfoList.add(aspectInfo);
        }
    }

    //框架中一定遵守给Aspect类添加@Aspect和@Order标签的规范，同时，必须继承自DefaultAspect.class
    //此外，@Aspect的属性值不能是它本身
    private boolean verifyAspect(Class<?> aspectClass) {
            return aspectClass.isAnnotationPresent(Aspect.class)&&
                    aspectClass.isAnnotationPresent(Order.class)&&
                    DefaultAspect.class.isAssignableFrom(aspectClass)&&
                    aspectClass.getAnnotation(Aspect.class).value()!=Aspect.class;
    }
}
